/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 *
 */

import path from 'path';

import { CoreTask, globalData, hvigorCore, TaskDetails } from '@ohos/hvigor';
import * as fse from 'fs-extra';

import { BuildDirConst } from '../../const/build-directory-const.js';
import { ArktSTaskConst, CommonConst, DefaultTargetConst } from '../../const/common-const.js';
import { InjectConst } from '../../const/inject-const.js';
import { ApiVersion } from '../../const/sdk-const.js';
import { ModuleType } from '../../enum/module-type-enum.js';
import { HarTargetUtil } from '../../utils/har-target-util.js';
import { HspTargetUtils } from '../../utils/hsp-target-utils.js';
import { InjectUtil } from '../../utils/inject-util.js';
import { hvigorOrToolChainsChanged } from '../../utils/meta-util.js';
import { limitMinApiVersion } from '../../utils/task-util.js';
import { packageHapDepends } from '../base/base-pack-hap-task.js';
import { BeforeGenerateDeviceCoverage } from '../before-generate-device-coverage.js';
import { BuildNativeWithCmake } from '../build-native-with-cmake.js';
import { BuildProfileTask } from '../build-profile-task.js';
import { CollectDebugSymbol } from '../collect-debug-symbol.js';
import { TaskNames } from '../common/task-names.js';
import { CompileResource } from '../compile-resource.js';
import { FastPackageHap } from '../fast-package.js';
import { GenerateDeviceCoverage } from '../generate-device-coverage.js';
import { GenerateLoaderJson } from '../generate-loader-json.js';
import { GenerateMetadata } from '../generate-metadata.js';
import { GeneratePkgContextInfo } from '../generate-pkg-context-info.js';
import { GeneratePkgModuleJson } from '../generate-pkg-module-json.js';
import { ArkLinter } from '../har/ark-linter.js';
import { CreateHarModuleInfo } from '../module-info/create-har-module-info.js';
import { HarBuildProfileTask } from '../har/har-build-profile-task.js';
import { PackageHar } from '../har/package-har.js';
import { PackageSignHar } from '../har/package-sign-har.js';
import { ProcessHarArtifacts } from '../har/process-har-artifacts.js';
import { ProcessObfuscationFiles } from '../har/process-obfuscation-files.js';
import { ProcessOhPackageJson } from '../har/process-oh-package-json.js';
import { ProcessPackageJson } from '../har/process-package-json.js';
import { PreviewHookCompileResource } from '../hook/preview-hook-compile-resource.js';
import { FastPackageHsp } from '../hsp/fast-package-hsp.js';
import { PackageHsp } from '../hsp/package-hsp.js';
import { PackageSharedHar } from '../hsp/package-shared-har.js';
import { PackageSharedTgz } from '../hsp/package-shared-tgz.js';
import { PrepareSharedHarRes } from '../hsp/prepare-shared-har-res.js';
import { SignHsp } from '../hsp/sign-hsp.js';
import { LegacyPackageHap } from '../legacy-tasks/legacy-package-hap.js';
import { MakePackInfo } from '../make-pack-info.js';
import { deviceTestComputeDepends } from './creation-util.js';
import { MergeProfile } from '../merge-profile.js';
import { GenerateOhosTestTemplate } from '../ohosTest/generate-ohos-test-template.js';
import { OhosTestCopyMockConfigJson } from '../ohosTest/ohos-test-copy-mock-config-json.js';
import { PackageHap } from '../package-hap.js';
import { PackageHqf } from '../package-hqf.js';
import { PreBuild } from '../pre-build.js';
import { PreCheckSyscap } from '../pre-check-syscap.js';
import { PreviewCompileResource } from '../preview-compile-resource.js';
import { PreviewUpdateAssets } from '../preview-update-assets.js';
import { CopyPreviewProfile } from '../previewer/copy-preview-profile.js';
import { ReplacePreviewerPage } from '../previewer/replace-previewer-page.js';
import { ProcessIntegratedHsp } from '../process-integrated-hsp.js';
import { ProcessProfile } from '../process-profile.js';
import { ProcessRouterMap } from '../process-router-map.js';
import { ProcessStartupConfig } from '../process-startup-config.js';
import { GlobalProjectDataService } from '../service/global-project-data-service.js';
import { TargetTaskService } from '../service/target-task-service.js';
import { SignHap } from '../sign-hap.js';
import { SignHqf } from '../sign-hqf.js';
import { SignModuleRemoteHsp } from '../sign-module-remote-hsp.js';
import { SignProjectRemoteHsp } from '../sign-project-remote-hsp.js';
import { SyscapTransform } from '../syscap-transform.js';
import { TargetTaskCreator } from '../task-creator.js';
import { BuildUnitTestHook } from '../unitTest/build-unit-test-hook.js';
import { GenerateUnitTestResult } from '../unitTest/generate-unit-test-result.js';
import { GenerateUnitTestTemplate } from '../unitTest/generate-unit-test-template.js';
import { ReplaceSourcemapInCoverageMode } from '../unitTest/replace-sourcemap-in-coverage-mode.js';
import { ReplaceUnitTestIndexFile } from '../unitTest/replace-unit-test-index-file.js';
import { UnitTestCopyMockConfigJson } from '../unitTest/unit-test-copy-mock-config-json.js';
import { UnitTestProcessProfile } from '../unitTest/unit-test-process-profile.js';
import { CreateModuleInfo } from '../module-info/create-module-info.js';

import Tasks = TaskNames.Task;
import CommonTask = TaskNames.CommonTask;

export class OhosTestCopyMockConfigJsonCA extends TargetTaskCreator {
  provider = () => new OhosTestCopyMockConfigJson(this.targetService);

  declareDepends = (): string[] => {
    if (this.targetService.verifyModuleVersionIsArkTS12()) {
      return  [Tasks.OHOS_TEST_COMPILE_ARKTS_EVOLUTION.name];
    } else {
      return  ['OhosTestCompileArkTS'];
    }
  };
  declareTaskDetail = () => TaskNames.Task.OHOS_TEST_COPY_MOCK_CONFIG_JSON;
}

export class UnitTestCopyMockConfigJsonCA extends TargetTaskCreator {
  provider = () => new UnitTestCopyMockConfigJson(this.targetService);

  declareDepends = (): string[] => ['UnitTestArkTS'];

  declareTaskDetail = () => TaskNames.Task.UNIT_TEST_COPY_MOCK_CONFIG_JSON;
}

export class PreBuildCA extends TargetTaskCreator {
  provider = () => new PreBuild(this.targetService);

  declareDepends = (): string[] => (hvigorOrToolChainsChanged(this.targetService.getSdkInfo()) ? [CommonTask.CLEAN.name] : []);

  declareTaskDetail = () => TaskNames.Task.PRE_BUILD;

  afterConfigure = () => {
    this.depends = this.declareDepends().map((depend) => `${this.node.getName()}:${depend}`);
  };
}

export class GenerateUnitTestTemplateCA extends TargetTaskCreator {
  provider = () => new GenerateUnitTestTemplate(this.targetService);

  declareDepends = (): string[] => [PreBuild.name];

  declareTaskDetail = () => TaskNames.Task.GENERATE_UNIT_TEST_TEMPLATE;
}

export class GenerateOhosTestTemplateCA extends TargetTaskCreator {
  provider = () => new GenerateOhosTestTemplate(this.targetService);

  declareDepends = (): string[] => [PreBuild.name];

  declareTaskDetail = () => TaskNames.Task.GENERATE_OHOS_TEST_TEMPLATE;
}

export class GenerateUnitTestResultCA extends TargetTaskCreator {
  provider = () => new GenerateUnitTestResult(this.targetService);

  declareDepends = () => {
    const depends = [this.isFa ? ArktSTaskConst.LEGACY_UNIT_TEST_ARKTS : ArktSTaskConst.UNIT_TEST_ARKTS];
    const depHspTargets = HspTargetUtils.calDepHspTargets(this.targetService);
    depHspTargets.forEach((target, hspName) => depends.push(`${hspName}:${target.getTargetName()}@${this.isFa ? 'LegacyUnitTestArkTS' : 'UnitTestArkTS'}`));
    return depends;
  };

  declareTaskDetail = () => TaskNames.Task.GENERATE_UNIT_TEST_RESULT;
}

export class GenerateDeviceCoverageCA extends TargetTaskCreator {
  provider = () => new GenerateDeviceCoverage(this.targetService);

  declareDepends = (): string[] => {
    const dependsList: string[] = [PreBuild.name];
    if (!globalData.cliOpts._.includes(CommonConst.ON_DEVICE_TEST)) {
      return dependsList;
    }

    // 测试框架仅支持default的target包
    if (this.targetService.getTargetData().getTargetName() !== 'default') {
      return dependsList;
    }

    // 测试框架如果发现模块内没有ohosTest的target则不挂载后续依赖
    if (!this.targetService.getModuleService().findTargetDataByName(DefaultTargetConst.OHOS_TEST_TARGET)) {
      return dependsList;
    }
    const ohosTestPath = path.resolve(
      path.resolve(this.targetService.getModuleService().getModuleModel().getProjectDir(), BuildDirConst.SRC),
      DefaultTargetConst.OHOS_TEST_TARGET,
    );

    // 测试框架如果发现模块内没有ohosTest目录则不挂载后续依赖
    if (!fse.existsSync(ohosTestPath)) {
      return dependsList;
    }
    const moduleType = this.targetService.getModuleService().getModuleModel().getModuleType();
    let depTask = '';
    if (moduleType === ModuleType.Entry || moduleType === ModuleType.Feature) {
      depTask = SignHap.name;
    } else if (moduleType === ModuleType.Shared) {
      depTask = SignHsp.name;
    } else if (moduleType === ModuleType.Har) {
      depTask = PackageHar.name;
    }
    depTask && deviceTestComputeDepends(dependsList, depTask, this.targetService, moduleType);
    dependsList.push(BeforeGenerateDeviceCoverage.name);
    return dependsList;
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.GENERATE_DEVICE_COVERAGE;
}

export class BeforeGenerateDeviceCoverageCA extends TargetTaskCreator {
  provider = () => new BeforeGenerateDeviceCoverage(this.targetService);

  declareDepends(): string[] {
    const dependsList: string[] = [PreBuild.name];
    const moduleType = this.targetService.getModuleService().getModuleModel().getModuleType();
    if (moduleType === ModuleType.Shared) {
      dependsList.push(SignHsp.name);
    }
    const depHspTargets = HspTargetUtils.calDepHspTargets(this.targetService);
    depHspTargets.forEach((targetData, moduleName) =>
      dependsList.push(`${moduleName}:${targetData.getTargetName()}@${TaskNames.Task.BEFORE_GENERATE_DEVICE_COVERAGE.name}`),
    );
    return dependsList;
  }

  declareTaskDetail = (): TaskDetails => TaskNames.Task.BEFORE_GENERATE_DEVICE_COVERAGE;
}

export class GeneratePkgContextInfoCA extends TargetTaskCreator {
  provider = () => new GeneratePkgContextInfo(this.targetService);

  declareDepends = (): string[] => {
    const depends = [PreBuild.name];
    if (this.targetService.getShouldBuildCmake() && this.targetService.getBuildOption().strictMode?.useNormalizedOHMUrl) {
      depends.push(BuildNativeWithCmake.name);
    }
    const localHarTargets = HarTargetUtil.calDepHarTargets(this.targetService);
    for (const [moduleName, targetName] of localHarTargets) {
      const targetService = this.targetService.getModuleService().getProjectModel().getTarget(moduleName, targetName);
      if (targetService && targetService.getShouldBuildCmake() && targetService.getBuildOption().strictMode?.useNormalizedOHMUrl) {
        depends.push(`${moduleName}:${targetName}@${BuildNativeWithCmake.name}`);
      }
    }
    return depends;
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.GENERATE_PKG_CONTEXT_INFO;
}

export class ProcessProfileCA extends TargetTaskCreator {
  provider = () => new ProcessProfile(this.targetService);

  declareDepends = (): string[] => [MergeProfile.name, GeneratePkgContextInfo.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PROCESS_PROFILE;
}

export class MergeProfileCA extends TargetTaskCreator {
  provider = () => new MergeProfile(this.targetService);

  declareDepends = (): string[] => {
    const moduleName = this.node.getName();
    const targetName = this.targetService.getTargetData().getTargetName();
    const depends: string[] = [`${moduleName}:${targetName}@${PreBuild.name}`];
    const depHspTargets = HspTargetUtils.calDepHspTargets(this.targetService);
    depHspTargets.forEach((target, hspName) => depends.push(`${hspName}:${target.getTargetName()}@${MergeProfile.name}`));
    const depHarTargets = HarTargetUtil.calDepHarTargets(this.targetService);
    depHarTargets.forEach((targetName, harName) => depends.push(`${harName}:${targetName}@${Tasks.MERGE_PROFILE.name}`));
    hvigorCore.isCommandEntryTask(TaskNames.Task.TEST.name) && depends.push(`${moduleName}:${targetName}@${TaskNames.Task.GENERATE_UNIT_TEST_TEMPLATE.name}`);
    return depends;
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.MERGE_PROFILE;

  afterConfigure = () => (this.depends = this.declareDepends());
}

export class HarBuildProfileTaskCA extends TargetTaskCreator {
  declareDepends = () => {
    const depends = [PreBuild.name];
    const buildProfileDepends = getBuildProfileEtsDependencies(this.targetService);
    return [...depends, ...buildProfileDepends];
  };

  declareTaskDetail = () => TaskNames.CommonTask.CREATE_HAR_BUILD_PROFILE;

  provider = () => new HarBuildProfileTask(this.targetService);
}

export class CreateHarModuleInfoCA extends TargetTaskCreator {
  declareDepends = () => [PreBuild.name];

  declareTaskDetail = () => TaskNames.CommonTask.CREATE_HAR_MODULE_INFO;

  provider = () => new CreateHarModuleInfo(this.targetService);
}

export class CreateModuleInfoCA extends TargetTaskCreator {
  declareDepends = () => [PreBuild.name];

  declareTaskDetail = () => TaskNames.CommonTask.CREATE_MODULE_INFO;

  provider = () => new CreateModuleInfo(this.targetService);
}

export class GenerateLoaderJsonCA extends TargetTaskCreator {
  provider = () => new GenerateLoaderJson(this.targetService);

  declareDepends = (): string[] => {
    const depends = [ProcessRouterMap.name, ProcessStartupConfig.name];

    if (this.targetService.getModuleService().getModuleModel().isHarModule()) {
      depends.push(CreateHarModuleInfo.name);
    } else if (this.targetService.getModuleService().getModuleModel().isHapModule() || this.targetService.getModuleService().getModuleModel().isHspModule()) {
      depends.push(CreateModuleInfo.name);
    }

    const depHspTargets = HspTargetUtils.calDepHspTargets(this.targetService);
    if (InjectUtil.isPreviewProcess()) {
      depHspTargets.forEach((targetData, hspName) => depends.push(`${hspName}:${targetData.getTargetName()}@${PreviewCompileResource.name}`));
    } else {
      depHspTargets.forEach((targetData, hspName) => depends.push(`${hspName}:${targetData.getTargetName()}@${CompileResource.name}`));
    }
    return depends;
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.GENERATE_LOADER_JSON;
}

export class ProcessRouterMapCA extends TargetTaskCreator {
  provider = () => new ProcessRouterMap(this.targetService);

  declareDepends = (): string[] => [GeneratePkgContextInfo.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PROCESS_ROUTER_MAP;
}

export class ProcessStartupConfigCA extends TargetTaskCreator {
  provider = () => new ProcessStartupConfig(this.targetService);

  declareDepends = (): string[] => [GeneratePkgContextInfo.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PROCESS_STARTUP_CONFIG;
}

export class PackageHapCA extends TargetTaskCreator {
  provider = () => new PackageHap(this.targetService);

  declareDepends = (): string[] => [GeneratePkgModuleJson.name, ProcessIntegratedHsp.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PACKAGE_HAP;
}

export class FastPackageCA extends TargetTaskCreator {
  provider = () => new FastPackageHap(this.targetService);

  declareDepends = (): string[] => [GeneratePkgModuleJson.name, ProcessIntegratedHsp.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.FAST_PACKAGE;
}

export class PackageHqfCA extends TargetTaskCreator {
  provider = () => new PackageHqf(this.targetService);

  declareDepends = (): string[] => [TaskNames.Task.PREPARE_QUICKFIX.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PACKAGE_HQF;
}

export class SignHqfCA extends TargetTaskCreator {
  provider = () => new SignHqf(this.targetService);

  declareDepends = (): string[] => [TaskNames.Task.PACKAGE_HQF.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.SIGN_HQF;
}

export class GeneratePkgModuleJsonCA extends TargetTaskCreator {
  provider = () => new GeneratePkgModuleJson(this.targetService);

  declareDepends = (): string[] => packageHapDepends(this.targetService);

  declareTaskDetail = (): TaskDetails => TaskNames.Task.GENERATE_PKG_MODULE_JSON;
}

export class CollectDebugSymbolCA extends TargetTaskCreator {
  provider = () => new CollectDebugSymbol(this.targetService);

  declareDepends = (): string[] => {
    const moduleModel = this.targetService.getModuleService().getModuleModel();
    const fastBuild = this.isFastBuild && hvigorCore.isCommandEntryTask(TaskNames.CommonHookTask.ASSEMBLE_APP.name);
    switch (true) {
      case moduleModel.isHapModule():
        return fastBuild ? [FastPackageHap.name] : [PackageHap.name];

      case moduleModel.isHspModule():
        return fastBuild ? [FastPackageHsp.name] : [PackageHsp.name];

      case moduleModel.isHarModule():
        return [PackageHar.name];

      default:
        return [];
    }
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.COLLECT_DEBUG_SYMBOL;
}

export class PackageHspCA extends TargetTaskCreator {
  provider = () => new PackageHsp(this.targetService);

  declareDepends = (): string[] => [GeneratePkgModuleJson.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PACKAGE_HSP;
}

export class FastPackageHspCA extends TargetTaskCreator {
  provider = () => new FastPackageHsp(this.targetService);

  declareDepends = (): string[] => [GeneratePkgModuleJson.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.FAST_PACKAGE_HSP;
}

export class SignHspCA extends TargetTaskCreator {
  provider = () => new SignHsp(this.targetService);

  declareDepends = (): string[] => [PackageHsp.name];

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.SIGN_HSP;
}

export class PackageSignHarCA extends TargetTaskCreator {
  provider = () => new PackageSignHar(this.targetService);

  declareDepends = (): string[] => [PackageHar.name];

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.PACKAGE_SIGN_HAR;
}

export class SignProjectRemoteHspCA extends TargetTaskCreator {
  provider = () => new SignProjectRemoteHsp(this.targetService);

  declareDepends = (): string[] => [ProcessIntegratedHsp.name, PreBuild.name];

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.SIGN_PROJECT_REMOTE_HSP;
}

export class SignModuleRemoteHspCA extends TargetTaskCreator {
  provider = () => new SignModuleRemoteHsp(this.targetService);

  declareDepends = (): string[] => {
    const projectOhpmPath = this.targetService.getModuleService().getProjectModel().getRemoteHspPath();
    return fse.existsSync(projectOhpmPath) ? [SignProjectRemoteHsp.name, ProcessIntegratedHsp.name] : [ProcessIntegratedHsp.name, PreBuild.name];
  };

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.SIGN_MODULE_REMOTE_HSP;
}

export class ProcessIntegratedHspCA extends TargetTaskCreator {
  provider = () => new ProcessIntegratedHsp(this.targetService);

  declareDepends = (): string[] => {
    return [PreBuild.name];
  };

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.PROCESS_INTEGRATED_HSP;
}

export class PackageSharedHarCA extends TargetTaskCreator {
  provider = () => new PackageSharedHar(this.targetService);

  declareDepends = (): string[] => [TaskNames.Task.PREPARE_SHARED_HAR_RES.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PACKAGE_SHARED_HAR;
}

export class PrepareSharedHarResCA extends TargetTaskCreator {
  provider = () => new PrepareSharedHarRes(this.targetService);

  declareDepends = (): string[] => {
    const isTestTarget = this.targetService.getTargetData().getTargetName() === DefaultTargetConst.OHOS_TEST_TARGET;
    return [isTestTarget ? 'OhosTestCompileArkTS' : 'CompileArkTS', TaskNames.Task.DO_NATIVE_STRIP.name];
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PREPARE_SHARED_HAR_RES;
}

export class PackageSharedTgzCA extends TargetTaskCreator {
  provider = () => new PackageSharedTgz(this.targetService);

  declareDepends = (): string[] => [SignHsp.name, PackageSharedHar.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PACKAGE_SHARED_TGZ;
}

export class PreviewCompileResourceCA extends TargetTaskCreator {
  provider = () => new PreviewCompileResource(this.targetService);

  declareDepends = (): string[] => [TaskNames.Task.PREVIEW_PROCESS_RESOURCE.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PREVIEW_COMPILE_RESOURCE;
}

export class PreviewUpdateAssetsCA extends TargetTaskCreator {
  provider = () => new PreviewUpdateAssets(this.targetService);

  declareDepends = (): string[] => ['buildPreviewerResource'];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PREVIEW_UPDATE_ASSETS;

  afterConfigure = () => {
    this.depends = this.declareDepends().map((depend) => `${this.node.getName()}:${depend}`);
  };
}

export class ReplacePreviewerPageCA extends TargetTaskCreator {
  provider = () => new ReplacePreviewerPage(this.targetService);

  declareDepends = (): string[] => {
    const depends = [PreviewHookCompileResource.name];

    // 1.处理资源增量编译时，restool不复制resouces目录，手动copy profile路由配置文件
    const compileResInc = hvigorCore.getExtraConfig().get(InjectConst.PREVIEWER_COMPILE_RES_INC);
    if (compileResInc === 'true') {
      depends.push(CopyPreviewProfile.name);
    }
    return depends;
  };

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.REPLACE_PREVIEWER_PAGES;
}

export class CopyPreviewProfileCA extends TargetTaskCreator {
  provider = () => new CopyPreviewProfile(this.targetService);

  declareDepends = (): string[] => [PreviewHookCompileResource.name];

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.COPY_PREVIEWER_PROFILE;
}

export class ReplaceUnitTestIndexFileCA extends TargetTaskCreator {
  provider = () => new ReplaceUnitTestIndexFile(this.targetService);

  declareDepends = (): string[] => [CompileResource.name];

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.REPLACE_UNIT_TEST_INDEX_FILE;
}

export class BuildUnitTestHookCA extends TargetTaskCreator {
  provider = () => new BuildUnitTestHook(this.targetService, false);

  declareDepends = (): string[] => {
    const depends = [GenerateLoaderJson.name, ReplaceUnitTestIndexFile.name];
    depends.push(PreCheckSyscap.name);
    return depends;
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.BUILD_UNIT_TEST_RES;
}

export class ReplaceSourceMapInCoverageModeCA extends TargetTaskCreator {
  provider = () => new ReplaceSourcemapInCoverageMode(this.targetService);

  declareDepends = (): string[] => {
    return ['UnitTestArkTS'];
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.REPLACE_SOURCEMAP_IN_COVERAGE_MODE;
}

export class SignHapCA extends TargetTaskCreator {
  provider = () => new SignHap(this.targetService);

  declareDepends = (): string[] => [this.isFa ? LegacyPackageHap.name : PackageHap.name];

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.SIGN_HAP;
}

export class PreCheckSyscapCA extends TargetTaskCreator {
  provider = () => new PreCheckSyscap(this.targetService, TaskNames.CommonTask.PRE_CHECK_SYSCAP);

  declareDepends = (): string[] => [PreBuild.name];

  declareTaskDetail = (): TaskDetails => TaskNames.CommonTask.PRE_CHECK_SYSCAP;
}

export class SyscapTransformCA extends TargetTaskCreator {
  provider = () => new SyscapTransform(this.targetService);

  declareDepends = (): string[] => [PreCheckSyscap.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.SYSCAP_TRANSFORM;
}

export class PackageHarCA extends TargetTaskCreator {
  declareDepends = () => {
    return [TaskNames.Task.PROCESS_HAR_ARTIFACTS.name];
  };

  declareTaskDetail = () => TaskNames.Task.PACKAGE_HAR;

  provider = (): CoreTask => new PackageHar(this.targetService);
}

export class ProcessHarArtifactsCA extends TargetTaskCreator {
  declareDepends = () => {
    const depends: string[] = [ProcessObfuscationFiles.name, TaskNames.Task.CACHE_NATIVE_LIBS.name];
    const useRollupETS: boolean = this.targetService.getSdkInfo().hasRollUpPluginInEtsLoader;
    depends.push(
      this.targetService.getModuleService().getModuleModel().isOhpmProject()
        ? TaskNames.Task.PROCESS_OH_PACKAGE_JSON.name
        : TaskNames.Task.PROCESS_PACKAGE_JSON.name,
    );

    if (this.targetService.verifyModuleVersionIsArkTS12()) {
      if (this.targetService.getTargetData().getTargetName() === 'ohosTest') {
        depends.push(TaskNames.Task.OHOS_TEST_COMPILE_ARKTS_EVOLUTION.name);
      } else {
        depends.push(TaskNames.Task.COMPILE_ARKTS_EVOLUTION.name);
      }
    } else {
      depends.push(this.targetService.isOpenSource() || useRollupETS ? 'HarCompileArkTS' : 'HarBuildArkTS');
    }

    depends.push(ProcessIntegratedHsp.name);
    return depends;
  };

  declareTaskDetail = () => TaskNames.Task.PROCESS_HAR_ARTIFACTS;

  provider = (): CoreTask => new ProcessHarArtifacts(this.targetService);
}

export class ProcessOhPackageJsonCA extends TargetTaskCreator {
  declareDepends = () => [PreBuild.name];

  declareTaskDetail = () => TaskNames.Task.PROCESS_OH_PACKAGE_JSON;

  provider = (): CoreTask => new ProcessOhPackageJson(this.targetService);
}

export class ProcessPackageJsonCA extends TargetTaskCreator {
  declareDepends = () => [PreBuild.name];

  declareTaskDetail = () => TaskNames.Task.PROCESS_PACKAGE_JSON;

  provider = (): CoreTask => new ProcessPackageJson(this.targetService);
}

export class ArkLinterCA extends TargetTaskCreator {
  declareDepends = () => {
    const depends: string[] = [ProcessProfile.name];
    if (limitMinApiVersion(this.targetService.getTargetData(), ApiVersion.API_VERSION_9)) {
      depends.push(TaskNames.CommonTask.CREATE_HAR_BUILD_PROFILE.name);
    }
    return depends;
  };

  declareTaskDetail = () => {
    return { name: 'LintArkTS' };
  };

  provider = () => new ArkLinter(this.targetService);
}

export class ProcessObfuscationFilesCA extends TargetTaskCreator {
  declareDepends = (): string[] => [CompileResource.name];

  declareTaskDetail = () => {
    return { name: ProcessObfuscationFiles.name };
  };

  provider = () => new ProcessObfuscationFiles(this.targetService);
}

export class GenerateMetadataCA extends TargetTaskCreator {
  declareDepends = (): string[] => {
    const hspGenerateMetadataTasks: string[] = [PreBuild.name];
    const depHspTargets = HspTargetUtils.calDepHspTargets(this.targetService);
    depHspTargets.forEach((targetData, hspName) =>
      hspGenerateMetadataTasks.push(`${hspName}:${targetData.getTargetName()}@${TaskNames.Task.GENERATE_METADATA.name}`),
    );

    const projectOhpmPath = this.targetService.getModuleService().getProjectModel().getRemoteHspPath();
    const moduleOhpmPath = this.targetService.getTargetData().getModuleModel().getRemoteHspPath();
    const moduleName = this.node.getName();

    // 判断当前target对应的module是否已经存在模块级remoteHsp签名任务
    const moduleRemoteHspSet: Set<string> = GlobalProjectDataService.getInstance().getModuleRemoteHspPromise();
    const ifHasModuleTask = moduleRemoteHspSet.has(moduleName);

    // 判断是否存在工程级与模块级的remoteHsp文件，如果没有则不执行SignModuleRemoteHsp任务
    if (fse.existsSync(projectOhpmPath) || fse.existsSync(moduleOhpmPath)) {
      // 如果当前target对应的module存在模块级remoteHsp签名任务则不再过多依赖避免重复签名
      if (!ifHasModuleTask) {
        GlobalProjectDataService.getInstance().setModuleRemoteHspPromise(moduleName);
        hspGenerateMetadataTasks.push(SignModuleRemoteHsp.name);
      }
    }
    return hspGenerateMetadataTasks;
  };

  declareTaskDetail = () => TaskNames.Task.GENERATE_METADATA;

  provider = () => new GenerateMetadata(this.targetService);
}

export class MakePackInfoCA extends TargetTaskCreator {
  declareDepends = () => [MergeProfile.name];

  declareTaskDetail = () => TaskNames.Task.MAKE_PACK_INFO;

  provider = () => new MakePackInfo(this.targetService);
}

export class UnitTestProcessProfileCA extends TargetTaskCreator {
  declareDepends = () => [ProcessProfile.name];

  declareTaskDetail = () => TaskNames.CommonTask.UNIT_TEST_PROCESS_PROFILE;

  provider = () => new UnitTestProcessProfile(this.targetService);
}

export class BuildProfileTaskCA extends TargetTaskCreator {
  declareDepends = () => {
    const depends = [PreBuild.name];
    const buildProfileDepends = getBuildProfileEtsDependencies(this.targetService);
    return [...depends, ...buildProfileDepends];
  };

  declareTaskDetail = () => TaskNames.CommonTask.CREATE_BUILD_PROFILE;

  provider = () => new BuildProfileTask(this.targetService);
}

/**
 * 获取依赖中的CreateBuildProfile、CREATE_HAR_BUILD_PROFILE任务
 */
export function getBuildProfileEtsDependencies(targetService: TargetTaskService): string[] {
  const depends: string[] = [];
  const depHspTargets = HspTargetUtils.calDepHspTargets(targetService);
  depHspTargets.forEach((targetData, hspName) => depends.push(`${hspName}:${targetData.getTargetName()}@${CommonTask.CREATE_BUILD_PROFILE.name}`));

  // 如果引用了本地har模块则额外调用har模块的CREATE_HAR_BUILD_PROFILE任务用于生成BuildProfile.ets文件
  const depHarTargets = HarTargetUtil.calDepHarTargets(targetService);
  depHarTargets.forEach((targetName, harName) => depends.push(`${harName}:${targetName}@${CommonTask.CREATE_HAR_BUILD_PROFILE.name}`));
  return depends;
}
